package kdd.feature;

import java.io.FileWriter;
import java.io.IOException;
import java.io.WriteAbortedException;
import java.sql.*;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;

import org.omg.CORBA.portable.ValueBase;

import kdd.lib.Lib;


public class FeatureExtraction {
	public String dbhost = null, dbname = null;
	private Connection conn;
	public static HashSet<String> allProjectId = null;
	EssayAbstraction essays;
	DonationAbstraction donations;
	ResourceAbstraction resources;
	ProjectAbstract projects;
	
	public HashMap<String, HashMap<String, Object> > features = 
			new HashMap<String, HashMap<String, Object> >();
	public static String trueString = "t";
	
	public static String requiredFeatures[] = {
		"at_least_1_teacher_referred_donor",
		"fully_founded",
		"at_least_1_green_donation",
		"great_chat",
		"three_or_more_non_teacher_referred_donors",
		"one_non_teacher_referred_donor_giving_100_plus",
		"donation_from_thoughtful_donor"
	};

	
	public static String usedFeatures[] = {
		"projectid",
		"score",
		"teacher_referred_donor",
		"total_price_excluding_optional_support",
		"total_item_price",
		"green_donation_num"
	};
	
	public static String usefulFeatures[] = {
		"essay_length",
		"poverty_level",
		"student_reached",
		"great_messages_proportion",
		"total_price_excluding_optional_support",
		"total_price_including_optional_support",
		"eligible_double_your_impact_match"
	};
	
	private int indexOf(String arr[], String x){
		for (int i = 0; i < arr.length; i++)
			if (arr[i].equals(x)) return i;
		Lib.assertTrue(false);
		return 0;
	}
	
	public void output() throws IOException {
		Set<String> keys = features.keySet();
		FileWriter outfile = new FileWriter("s:/outputFeature.tsv");
		for (String str: usedFeatures) outfile.write(str + "\t");
		outfile.write("\n");
		for (String key: keys) {
			HashMap<String, Object> feature = features.get(key);
			for (String str: usedFeatures)
				outfile.write("\t" + feature.get(str));
			outfile.write("\n");
		}
		outfile.close();
	}
	
	private HashMap<String, Object> getFeatureMap(String projectid){
		HashMap<String, Object> ret = features.get(projectid);
		if (ret == null) {
			ret = new HashMap<String, Object>();
			features.put(projectid, ret);
		}
		return ret;
	}
	
	private void mergeFeature(String name, HashMap<String, Object> feature){
		for (String key: allProjectId)
			features.get(key).put(name, fixNull((Double)feature.get(key)));
	}
	
	private void incMapValue(HashMap<String, Object> map, String key, double x){
		Double value = (Double)map.get(key);
		if (value == null) {
			map.put(key, x);
			return;
		}
		map.put(key, value + x);
	}
	
	private Double fixNull(Object object){
		return object == null? 0 : (Double)object;
	}
	
	private void getBasic() throws SQLException{
		/**
		 * get projectid
		 */	
		for (String key: allProjectId)
			features.get(key).put("projectid", key);
			
		/**
		 * get at_least_1_teacher_referred_donor
		 */
		HashMap<String, Object> allTeacherNum = donations.getTotalTeacherDonorNum();
		mergeFeature("teacher_referred_donor", allTeacherNum);
		for (String key: allProjectId)
			incMapValue(features.get(key), "score", fixNull(allTeacherNum.get(key)) > 0.5 ? 1 : 0);
			
		/**
		 * get total_price_excluding_optional_support
		 */
		HashMap<String, Object> allTotalSupport = projects.getTotalSupportExclusive();
		mergeFeature("total_price_excluding_optional_support", allTotalSupport);
		
		/**
		 * get fully_founded
		 */
		HashMap<String, Object> allTotalPrice = resources.getTotalPrice();
		mergeFeature("total_item_price", allTotalPrice);
		for (String key: allProjectId)
			incMapValue(features.get(key), "score", 
					fixNull(allTotalPrice.get(key)) <= fixNull(allTotalSupport.get(key)) ? 1 : 0);
		
		/**
		 * get at_least_1_green_donation
		 */
		HashMap<String, Object> allGreenNum = donations.getTotalGreenDonation();
		mergeFeature("green_donation_num", allGreenNum);
		for (String key: allGreenNum.keySet())
			incMapValue(features.get(key), "score", (Double)allGreenNum.get(key) > 0.5 ? 1 : 0);
		
		/**
		 * get great_chat
		 */
		for (String key: allProjectId)
			incMapValue(features.get(key), "score", 1);
		
		
		/**
		 * three_or_more_non_teacher_referred_donors
		 * one_non_teacher_referred_donor_giving_100_plus
		 * donation_from_thoughtful_donor(discarded)
		 */
		HashMap<String, Object> allNonTeacherNum = donations.getTotalNonTeacherDonorNum(),
				allNonGive100Num = donations.getTotalNonTeacherDonorGiven100Num();
		mergeFeature("non_teacher_refered_donors", allNonTeacherNum);
		mergeFeature("non_teacher_referred_donors_give_100_plus", allNonGive100Num);
		for (String key: allProjectId)
			if (fixNull(allNonTeacherNum.get(key)) > 2.5 || 
					fixNull(allNonGive100Num.get(key)) > 0.5) 
				incMapValue(features.get(key), "score", 1);
	}
	
	private String getNQuestionMark(int N){
		String ret = "?";
		while (--N > 0) ret += ",?";
		return ret;
	}
	
	public FeatureExtraction(String host, String database) throws ClassNotFoundException, SQLException{
		dbhost = host;
		dbname = database;
		connectToHost();
		donations = new DonationAbstraction(conn);
		resources = new ResourceAbstraction(conn);
		essays = new EssayAbstraction(conn);
		projects = new ProjectAbstract(conn);
		allProjectId = projects.getAllProjectid();
		for (String key: allProjectId)
			features.put(key, new HashMap<String, Object>());
	}
	
	private void execute(String query, String arg0) throws SQLException{
		PreparedStatement stmt = conn.prepareStatement(query);
		stmt.setString(1, arg0);
		stmt.execute();
	}
	
	private void connectToHost() throws ClassNotFoundException, SQLException{
		Class.forName("com.mysql.jdbc.Driver");
		conn = DriverManager.getConnection("jdbc:mysql://" + dbhost + ":3306/", "root", "");
		conn.prepareStatement("use kdd;").execute();
	}
	
	public void extract() throws SQLException{
		getBasic();
	}


}
